package com.jaws.demo.schedule.quartz;

import com.jaws.core.common.log.Log;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;

import java.util.Date;

/**
 * 对JOb操作的核心类
 * 
 * @author maojian
 * @date 2017-09-21 11:34:54
 * @since v1.0.0
 */
public final class DynamicSchedulerFactory implements InitializingBean {

	private static final Logger logger = LoggerFactory.getLogger(DynamicSchedulerFactory.class);

	private static Scheduler scheduler;

	public DynamicSchedulerFactory() {
	}

	public void setScheduler(Scheduler scheduler) {
		if (DynamicSchedulerFactory.scheduler == null) {
			DynamicSchedulerFactory.scheduler = scheduler;
		}
	}

	public static boolean registerOrUpdateJob(DynamicJob job) throws SchedulerException{
		final TriggerKey triggerKey = job.triggerKey();
		if (scheduler.checkExists(triggerKey)) {
			return updateJob(job);
		}else{
			return registerJob(job);
		}
	}
	
	public static boolean updateJob(DynamicJob job) throws SchedulerException {
		final TriggerKey triggerKey = job.triggerKey();
		final CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(job.cronExpression());
		final CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(cronScheduleBuilder).build();
		scheduler.rescheduleJob(triggerKey, cronTrigger);
		return true;
	}
	
	/**
	 * 添加(注册)一个动态的JOB
	 * 
	 * @author maojian
	 * @date 2017-11-02 11:26:54
	 * @since v1.0.0
	 * @param job
	 * @return
	 * @throws SchedulerException
	 */
	public static boolean registerJob(DynamicJob job) throws SchedulerException {
		final String OP = "DynamicSchedulerFactory.registerJob";
		final TriggerKey triggerKey = job.triggerKey();
		if (scheduler == null) {
			logger.warn(Log.op(OP).msg("调度器没有初始化，请检查相关配置").toString());
			return false;
		}

		if (scheduler.checkExists(triggerKey)) {
			final Trigger trigger = scheduler.getTrigger(triggerKey);
			throw new SchedulerException("Already exist trigger [" + trigger + "] by key [" + triggerKey + "] in Scheduler");
		}

		final CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(job.cronExpression());
		final CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(cronScheduleBuilder).build();

		final JobDetail jobDetail = job.jobDetail();
		final Date date = scheduler.scheduleJob(jobDetail, cronTrigger);

		logger.info(Log.op(OP).msg("job注册成功").kv("job", job).kv("date", date).toString());
		return true;
	}

	/**
	 * 更新一个动态的JOB
	 * 
	 * @author maojian
	 * @date 2017-11-02 11:27:07
	 * @since v1.0.0
	 * @param job
	 * @return
	 * @throws SchedulerException
	 */
//	public static boolean updateJob(DynamicJob job) throws SchedulerException {
//
//		removeJob(job);
//
//		boolean registerJob = registerJob(job);
//		logger.info(Log.op("DynamicSchedulerFactory.updateJob").kv("job", job).kv("success", registerJob).toString());
//		return true;
//	}

	/**
	 * 暂停已经存在的JOB
	 * 
	 * @author maojian
	 * @date 2017-11-02 11:07:14
	 * @since v1.0.0
	 * @param existJob
	 * @return
	 * @throws SchedulerException
	 */
	public static boolean pauseJob(DynamicJob existJob) throws SchedulerException {
		final String OP = "DynamicSchedulerFactory.pauseJob";
		final TriggerKey triggerKey = existJob.triggerKey();
		boolean result = false;
		if (scheduler.checkExists(triggerKey)) {
			scheduler.pauseTrigger(triggerKey);
			result = true;
			logger.info(Log.op(OP).msg("Pause exist DynamicJob successful").kv("DynamicJob", existJob).kv("triggerKey", triggerKey).toString());
		} else {
			logger.info(Log.op(OP).msg("Pause exist DynamicJob Failed").kv("DynamicJob", existJob).kv("triggerKey", triggerKey).toString());
		}
		return result;
	}

	/**
	 * 重启一个JOB
	 * 
	 * @author maojian
	 * @date 2017-11-02 11:06:54
	 * @since v1.0.0
	 * @param existJob
	 * @return
	 * @throws SchedulerException
	 */
	public static boolean resumeJob(DynamicJob existJob) throws SchedulerException {
		final String OP = "DynamicSchedulerFactory.resumeJob";

		final TriggerKey triggerKey = existJob.triggerKey();
		boolean result = false;
		if (scheduler.checkExists(triggerKey)) {
			final CronTrigger newTrigger = existJob.cronTrigger();
			scheduler.rescheduleJob(triggerKey, newTrigger);
			result = true;
			logger.info(Log.op(OP).msg("Resume exist DynamicJob successful").kv("DynamicJob", existJob).kv("triggerKey", triggerKey).toString());
		} else {
			logger.info(Log.op(OP).msg("Resume exist DynamicJob Failed").kv("DynamicJob", existJob).kv("triggerKey", triggerKey).toString());
		}
		return result;
	}

	/**
	 * 检查JOB是否存在
	 * 
	 * @author maojian
	 * @date 2017-11-02 11:07:38
	 * @since v1.0.0
	 * @param job
	 * @return
	 * @throws SchedulerException
	 */
	public static boolean existedJob(DynamicJob job) throws SchedulerException {
		final TriggerKey triggerKey = job.triggerKey();
		return scheduler.checkExists(triggerKey);
	}

	/**
	 * 删除一个已经存在的JOB
	 * 
	 * @author maojian
	 * @date 2017-11-02 11:08:17
	 * @since v1.0.0
	 * @param existJob
	 * @return
	 * @throws SchedulerException
	 */
	public static boolean removeJob(DynamicJob existJob) throws SchedulerException {
		final String OP = "DynamicSchedulerFactory.removeJob";

		final TriggerKey triggerKey = existJob.triggerKey();
		boolean result = false;
		if (scheduler.checkExists(triggerKey)) {
			final JobDetail jobDetail = existJob.jobDetail();
			result = scheduler.deleteJob(jobDetail.getKey());
		}

		logger.info(Log.op(OP).msg("Remove DynamicJob").kv("DynamicJob", existJob).kv("result", result).toString());
		return result;
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		Assert.notNull(scheduler, "scheduler is null");
		logger.info(Log.op("DynamicSchedulerFactory.afterPropertiesSet").msg("Initial DynamicSchedulerFactory successful").kv("scheduler", scheduler).toString());
	}

}